package hu.myai.runtimeneural;

import hu.myai.model.db.AxEstimation;
import hu.myai.util.DatabaseUtil;
import hu.myai.util.SanfordNet;

import java.io.File;
import java.util.Date;

import org.joone.engine.Layer;
import org.joone.io.MemoryInputSynapse;
import org.joone.io.MemoryOutputSynapse;
import org.joone.log.ILogger;
import org.joone.log.LoggerFactory;
import org.joone.net.NeuralNet;

public abstract class ExecuteNeuralNetwork {

	private static final ILogger log = LoggerFactory.getLogger(ExecuteNeuralNetwork.class);

	private MemoryOutputSynapse memOut;

	private boolean enableLogging;

	public NeuralNet nnet;

	public AxEstimation estimation = null;

	// for database util reference
	private DatabaseUtil dbUtil = new DatabaseUtil();

	private SanfordNet netUtil = new SanfordNet();

	public ExecuteNeuralNetwork(NeuralNet nnet) {
		this.nnet = nnet;
		enableLogging = !"false".equals(System.getProperty("enableLogging"));
	}

	public void Go(String symbol, String nnetFileName, double[][] historyArray) {

		if (nnet != null) {

			/*
			 * We get the first layer of the net (the input layer), then remove
			 * all the input synapses attached to it and attach a
			 * MemoryInputSynapse
			 */

			int timeSeries = netUtil.getTimeSeries();

			Layer input = nnet.getInputLayer();
			input.removeAllInputs();

			if (historyArray == null)
				historyArray = dbUtil.getHistoryForExecute(SanfordNet.getStartDate(), symbol);

			if (historyArray == null) {
				log.error("Error - No history for this entry: " + symbol + "  since: " + SanfordNet.getStartDate());
				throw new org.joone.exception.JooneRuntimeException("No history for this entry: " + symbol
						+ "  since: " + SanfordNet.getStartDate());
			}

			if (historyArray.length < timeSeries + 1) {
				log.error("Error - Not enough history for this entry: " + symbol + " " + historyArray.length);
				throw new org.joone.exception.JooneRuntimeException("Not enough history for this entry: " + symbol
						+ " " + historyArray.length);
			}

			MemoryInputSynapse inputData = netUtil.createInput(historyArray, 1, 2, 8);
			input.addInputSynapse(inputData);

			/*
			 * We get the last layer of the net (the output layer), then remove
			 * all the output synapses attached to it and attach a
			 * MemoryOutputSynapse
			 */

			Layer output = nnet.getOutputLayer();
			output.removeAllOutputs();
			memOut = new MemoryOutputSynapse();
			output.addOutputSynapse(memOut);

			// Now we interrogate the net once with four input patterns
			nnet.getMonitor().setTotCicles(1);
			nnet.getMonitor().setValidationPatterns(historyArray.length);
			nnet.getMonitor().setPreLearning(timeSeries);
			nnet.getMonitor().setLearning(false);
			nnet.getMonitor().setValidation(true);

			nnet.start();
			nnet.getMonitor().Go();

			// wait for resuls
			int cc = nnet.getMonitor().getValidationPatterns();
			double[][] patternArray = new double[3][cc];

			for (int i = 0; i < cc; ++i) {

				// Read the next pattern and print out it
				double[] pattern = memOut.getNextPattern();
				patternArray[0][i] = pattern[0];
				patternArray[1][i] = pattern[1];
				patternArray[2][i] = pattern[2];
			}

			nnet.stop();

			Date date = new Date();
			date.setTime(Math.round(historyArray[historyArray.length - 1][0]));

			Date lastDate = new Date();
			lastDate.setTime(Math.round(historyArray[historyArray.length - 2][0]));

			String normNetName = nnetFileName.substring(nnetFileName.lastIndexOf(File.separator) + 1);

			AxEstimation lastEstimation = dbUtil.getSavedEstimation(lastDate, symbol, normNetName);

			double avg = (patternArray[0][cc - 1] + patternArray[1][cc - 1] + patternArray[2][cc - 1]) / 3;
			double avgPrev = (patternArray[0][cc - 2] + patternArray[1][cc - 2] + patternArray[2][cc - 2]) / 3;

			double error = 0;
			if (lastEstimation != null) {
				double avgSaved = (lastEstimation.getEstimation1() + lastEstimation.getEstimation2() + lastEstimation
						.getEstimation3()) / 3;

				error = Math.abs(avgPrev - avgSaved);

			}

			estimation = new AxEstimation();

			estimation.setError(error);
			estimation.setEstimation1(patternArray[0][cc - 1]);
			estimation.setEstimation2(patternArray[1][cc - 1]);
			estimation.setEstimation3(patternArray[2][cc - 1]);
			estimation.setNnet(normNetName);
			estimation.set_date(date);
			estimation.set_symbol(symbol);

			// if (enableLogging && patternArray[0][cc - 1]< 0.1) {
			log.info(symbol + "  date:  " + date + "  buy/sell:  " + netUtil.trim(patternArray[0][cc - 1])
					+ "  Est2:  " + netUtil.trim(patternArray[1][cc - 1]) + "  Est3:  "
					+ netUtil.trim(patternArray[2][cc - 1]));
			// }

			// log.info("Done: " + SanfordNet.trim(avg) + " +-" + error);
		}
	}
}
